//
// Created by xuyang on 2019/1/13.
//

#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
static const int CONTROL_LEN = CMSG_LEN(sizeof(int));
//计算cmsg_len的值
/*发送文件描述符 sv参数是用来传递信息的UNIX域socket，
*fd参数是待发送的文件描述符    */
void send_fd(int sv, int fd)
{
    struct msghdr msg;
    struct iovec iov[1];

    char buf[0];
    iov[0].iov_base = buf;
    iov[0].iov_len = 1;
//不需要传递其他数据，所以iov数据部分为空
    msg.msg_name = "123123123";
    msg.msg_namelen = 0;
//面向连接，可以不用
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    struct cmsghdr* cm;
    cm=CMSG_FIRSTHDR(&msg);
    cm->cmsg_len = CONTROL_LEN;
//用CMSG_LEN()宏获得的值
    cm->cmsg_level = SOL_SOCKET;
    cm->cmsg_type = SCM_RIGHTS;
    //设置信息类型
    *(int*)CMSG_DATA(&cm) = fd;
//将要传递的文件描述符赋值给cmsghdr的数据部分
//    msg.msg_control = &cm;
//给msg_control分配设置好的cmsghdr结构体
    sendmsg(sv, &msg, 0);
//调用sendmsg()
};

int recv_fd(int sv)
{
    struct msghdr msg;
    struct iovec iov[1];

    char buf[0];
    iov[0].iov_base = buf;
    iov[0].iov_len = 1;
//没有其他要接受的数据，iovec数据部分设为空
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
//面向连接，不需要
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;

    struct cmsghdr cm;
    msg.msg_control = &cm;
    msg.msg_controllen = CONTROL_LEN;
//创建一个cmsghdr结构体，并分配给msg_control

    recvmsg(sv, &msg, 0);
//调用recvmsg()

    int fd = *(int*)CMSG_DATA(&cm);
//从cmsghdr的数据部分获取文件描述符

    return fd;
}


int main(int argc, char* argv[])
{
    int sv[2];
    int fd= 0;
/*创建父子进程管道*/
    int ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv);
    assert(ret != -1);
//将创建的管道符存于sv[2]中

    pid_t pid = fork();
    if(pid == 0)//子进程
    {
        close(sv[0]);//关闭管道符一端

        fd = open("a.txt", O_RDWR);
        printf("child fd:%d\n",fd);
        //  创建一个文件描述符
        send_fd(sv[1], (fd > 0) ? fd: 0);
        //在管道符另一端发送文件描述符
//        close(sv[1]);
        //关闭文件
        exit(0);
    }

//父进程
    close(sv[1]);//关闭管道符一端
    fd= recv_fd(sv[0]);
//在管道符另一端发送文件描述符
    char buf[1024];
    memset(buf, '\0', 1024);
    read(fd, buf, 1024);
    printf("I got fd %d and data %s\n", fd, buf);
//从文件中读取数据
//    close(fd);

    return 0;
}

